/**
 * @description JxStore，是对localStore和sessionStore的简单封装，对对象和数组做了检测和自动转换。
 * 对外暴露出vhLocalStore和vhSessionStore两个实例，实现完全一致，只是操作的对象是localStorage和sessionStorage的区别。
 * @example
 * import {vhLocalStore,vhSessionStore} from 'vhall-utils'
 * this.$jxUtils.vhLocalStore.set('userInfo',{nickname:'abc'})
 * this.$jxUtils.vhLocalStore.get('userInfo') // 拿到 {nickname:'abc'}
 * this.$jxUtils.vhLocalStore.get('userInfo',{raw:true}) // 拿到 `{"nickname":"abc"}`
 * this.$jxUtils.vhSessionStore.set('userInfo',{nickname:'abc'})
 * ...
 */
class JxStore {
  constructor(storage = window.localStorage) {
    this.storage = storage
    this.prefix = ''
  }

  setPrefix(prefix) {
    this.prefix = prefix
  }

  _pullData(key, options = {}) {
    return this.storage.getItem(key)
  }

  _pushData(key, value) {
    this.storage.setItem(`${this.prefix}${key}`, value)
  }

  _typeData2String(data) {
    if (data === null || data === undefined) return data
    if (Array.isArray(data) || typeof data === 'object') return JSON.stringify(data)
    return data
  }

  _string2TypeData(data) {
    if (data === null || data === undefined) return data

    // 使用validator.isObject/isArray 来判断
    const isLikeObject = data.startsWith('{') && data.endsWith('}')
    const isLikeArray = data.startsWith('[') && data.endsWith(']')

    if (isLikeObject || isLikeArray) return JSON.parse(data)
    return data
  }

  /**
   * @param {string} key key值
   * @description 检查是否包含某个key值
   * @returns {Boolean} 是否包含
   * @author ningkang.he
   * @example
   * this.$jxUtils.vhLocalStore.has('nickname') // true
   */
  has(key) {
    const value = this.storage.getItem(key)
    return value !== null && value !== undefined
  }

  /**
   * @param {string} key key
   * @param {any} value 值
   * @author ningkang.he
   * @example
   * this.$jxUtils.vhLocalStore.set('nickname',{nickname:'abc'}) // 可以直接设置对象
   */
  set(key, value) {
    const storeData = this._typeData2String(value)
    this._pushData(key, storeData)
  }

  /**
   *
   * @param {string} key
   * @param {object} options
   * @param {boolean} options.raw 是否获取原生值，而不转换数据
   * @returns {any} 获得存储的值
   * @author ningkang.he
   * @description 通过key来获取store中的值，获取时如果检测到是对象或数组形式将自动转成对象、数组
   * @example
   * this.$jxUtils.vhLocalStore.get('nickname') // 返回对象 {nickname:'abc'}
   * this.$jxUtils.vhLocalStore.get('userInfo',{raw:true}) // 配置raw来拿到字符串 `{"nickname":"abc"}`
   */
  get(key, options = {}) {
    const rawData = this._pullData(key, options)
    return options.raw ? rawData : this._string2TypeData(rawData)
  }

  /**
   * @param {string} key
   * @description 根据key值删除一条数据
   * @author ningkang.he
   * @example
   * this.$jxUtils.vhLocalStore.remove('userInfo')
   */
  remove(key) {
    return this.storage.removeItem(key)
  }
}

const vhLocalStore = new JxStore(window.localStorage)
const vhSessionStore = new JxStore(window.sessionStorage)

export { vhLocalStore, vhSessionStore }
